#ifndef _MAIN_SERVER_HPP
#define _MAIN_SERVER_HPP

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <error.h>
#include <cstring>
#include <iostream>
#include <unistd.h>
#include <thread>
#include <vector>
#include "Reactor.hpp"
#include "Client.hpp"
#include "NetEvent.hpp"
#include <condition_variable>
#include <mutex>
#include <functional>
#include <chrono>

using namespace std;

class MainServer : public NetEvent {
public:
    MainServer() = default;
    ~MainServer() = default;

    using EVENTSC = std::function<void(Client*)>;
    using EVENTRECV = std::function<void(Client*, const char*, int)>;

    void On(const string& event, const EVENTSC& callback) {
        if (event == "connect") {
            _connectFn = callback;
        } else if (event == "close") {
            _closeFn = callback;
        }
    }

    void On(const EVENTRECV& callback) {
        _recvFn = callback;
    }

    void onConnect(Client* c) override {
        //cout << "listen thread accept connection fd:" << c->Sockfd() << endl;
        _connectFn(c);
    }

    void onReceive(Client* c, const char* buf, int reactorId) override {
        //cout << "recvfrom client fd: " << c->Sockfd() << " data:" << buf << endl;
        //const char* ret = "hello,world";
        //c->PushData(ret, (int)strlen(ret));
        _recvFn(c, buf, reactorId);
    }

    void onClose(Client* c) override {
        //cout << "client disconnect fd:" << c->Sockfd() << endl;
        cout << "thread_id:" << this_thread::get_id() << endl;
        _closeFn(c);
    }

    void createServer(const char* ip, int port) {
        saveIpPort(ip, port);
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd == -1) {
            cout << "createServer socket() error" << strerror(errno) << endl;
            exit(0);
        }
        socklen_t socket_len = 1;
        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void*)&socket_len, sizeof(socket_len));

        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_port);
        if (_ip) {
            addr.sin_addr.s_addr = inet_addr(_ip);
        } else {
            addr.sin_addr.s_addr = INADDR_ANY;
        }
        socklen_t addrlen = sizeof(addr);
        int ret = bind(_sockfd, (sockaddr*)&addr, addrlen);
        if (ret) {
            cout << "createServer bind() error" << strerror(errno) << endl;
            exit(0);
        }

        ret = listen(_sockfd, 128);
        if (ret) {
            cout << "createServer bind() error" << strerror(errno) << endl;
            exit(0);
        }
        //打印端口号信息
        Info();
    }

    void Start(int threadNum = 2) {
        std::lock_guard<std::mutex> lock(_mutex);
        if (!_runFlag) {
            _runFlag = true;
            std::thread t(&MainServer::Run, this);
            t.detach();
        }

        _serverNum = threadNum;
        for (int i = 0; i < _serverNum; i++) {
            auto r = new Reactor(this, _reactorId++);
            _reactors.push_back(r);
            r->Start();
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    }

    void Run() {
        cout << "listening thread start cid:" << std::this_thread::get_id() << endl;
        _epollfd = epoll_create(1024);
        if (_epollfd == -1) {
            cout << "createServer epoll_create() error" << strerror(errno) << endl;
            exit(0);
        }
        epoll_event ev;
        ev.data.fd = _sockfd;
        ev.events = EPOLLIN;
        if (epoll_ctl(_epollfd, EPOLL_CTL_ADD, _sockfd, &ev)) {
            cout << "createServer epoll_ctl() error" << strerror(errno) << endl;
        }
        _evs = new epoll_event[_mEvents];
        while (_runFlag) {
            int ret = epoll_wait(_epollfd, _evs, _mEvents, 1);
            if (ret <  0) {
                if (ret == 0) continue;
                if (ret == -1) {
                    if (errno == EINTR) continue;
                     cout << "createServer epoll_wait() error" << strerror(errno) << endl;
                     break;
                }
            } else {
                for (int i = 0; i < ret; i++) {
                    if (_evs[i].data.fd == _sockfd) {
                        if (_evs[i].events & EPOLLIN) {
                            Accept();
                        }
                    }
                }
            }
        }
        std::unique_lock<std::mutex> lock(_mutex);
        cout << "listening thread quit" << endl;
        _exitStatus = 1;
        _cond.notify_one();
    }

    void Exit() {
        std::unique_lock<std::mutex> lock(_mutex);
        if (_runFlag) {
            _runFlag = false;
            _cond.wait(lock, [this] {
                return _exitStatus == 1;
            });
            close(_sockfd);
            close(_epollfd);
            delete _evs;
            for (auto &itr : _reactors) {
                itr->Exit();
            }
            _reactors.clear();
        }
    }

    std::vector<Reactor*> getReactors() {
        return _reactors;
    }

private:
    void saveIpPort(const char* ip, int port) {
        _ip = ip;
        _port = port;
    }

    void Info() {
        cout << "server is running on " << _ip << ":" << _port << endl;
    }

    void Accept() {
        sockaddr client;
        socklen_t client_len = sizeof(client);
        int connId = accept(_sockfd, &client, &client_len);
        if (connId > 0) {
            auto c = new Client(connId);
            AddClient(c);
        }
    }

    void AddClient(Client* c) {
        auto r = _reactors[_gid++ % _serverNum];
        r->AddClient(c);
        cout << "添加客户端到监听线程了" << endl;
    }

    int _sockfd {0};
    int _epollfd {0};
    epoll_event* _evs;
    const char* _ip {nullptr};
    int _port {};
    bool _runFlag {false};
    int _serverNum {0};
    int _mEvents {1024};
    std::vector<Reactor*> _reactors;
    int _gid {0};
    std::mutex _mutex;
    int _exitStatus {0};
    std::condition_variable _cond;
    EVENTRECV _recvFn;
    EVENTSC _connectFn;
    EVENTSC _closeFn;
    int _reactorId {1};
};

#endif
